{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']\n",
      "['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']\n"
     ]
    }
   ],
   "source": [
    "# 使用多个界定符分割字符串\n",
    "# string 对象的 split() 方法只适应于非常简单的字符串分割情形，\n",
    "# 它并不允许有多个分隔符或者是分隔符周围不确定的空格。\n",
    "# 当你需要更加灵活的切割字符串的时候，最好使用 re.split() 方法\n",
    "import re\n",
    "line = 'asdf fjdk; afed, fjek,asdf, foo'\n",
    "\n",
    "print(re.split(r'[;,\\s]\\s*', line))\n",
    "\n",
    "# 获取分割字符\n",
    "print(re.split(r'(;|,|\\s)\\s*', line))\n",
    "\n",
    "# 不想保留分割字符串到结果列表中去，但仍然需要使用到括号来分组正则表达式\n",
    "print(re.split(r'(?:,|;|\\s)\\s*', line))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 字符串类型及其操作 \n",
    "# 字符串可以用 + 运算符连接在一起，用 * 运算符重复\n",
    "name = \"TangQuanwei\"\n",
    "num = 20203206222\n",
    "print('my name is %s' % name)  # 旧式格式化方法\n",
    "print('my num is %d' % num)\n",
    "print(name+name)\n",
    "print(name*5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# r后面的 \\ 不转义\n",
    "print(r\"hahahhaha\\nas\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 字符串格式化\n",
    "print(\"{:,.2f}\".format(1234567.98765))\n",
    "# 整数格式化\n",
    "print(\"{0:b},{0:c},{0:d},{0:o},{0:x},{0:X}\".format(425))\n",
    "# 浮点数格式化\n",
    "print(\"{0:e},{0:E},{0:f},{0:%}\".format(3.14))\n",
    "# 简单的格式化\n",
    "name = \"唐权威\"\n",
    "print(f'我的名字叫：{name}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['foo.c', 'spam.c', 'spam.h']\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# 字符串开头或结尾匹配\n",
    "filenames = ['Makefile', 'foo.c', 'bar.py', 'spam.c', 'spam.h']\n",
    "\n",
    "# 可以匹配多个\n",
    "print([name for name in filenames if name.endswith(('.c', '.h'))])\n",
    "\n",
    "print(any(name.endswith('.py') for name in filenames))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "yes\n",
      "['11/27/2012', '3/13/2013']\n",
      "('11', '27', '2012')\n",
      "m:11, d:27, y:2012\n",
      "[('11', '27', '2012'), ('3', '13', '2013')]\n"
     ]
    }
   ],
   "source": [
    "# 匹配或者搜索特定模式的文本\n",
    "import re\n",
    "# 使用同一个模式去做多次匹配\n",
    "datepat = re.compile(r'\\d+/\\d+/\\d+')\n",
    "\n",
    "text1 = '11/27/2012'\n",
    "# match从字符串开始去匹配\n",
    "print('yes' if datepat.match(text1) else 'no')\n",
    "\n",
    "text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'\n",
    "\n",
    "res=datepat.findall(text)\n",
    "print(res)\n",
    "\n",
    "# 利用括号去捕获分组\n",
    "datepat = re.compile(r'(\\d+)/(\\d+)/(\\d+)')\n",
    "\n",
    "m = datepat.match('11/27/2012')\n",
    "print(m.groups())\n",
    "month, day, year = m.groups()\n",
    "print(f'm:{month}, d:{day}, y:{year}')\n",
    "\n",
    "# finditer 以迭代方式返回匹配\n",
    "print([i.groups() for i in datepat.finditer(text)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Today is 2012年11月27日. PyCon starts 2013年3月13日.\n",
      "Today is 2012-11-27. PyCon starts 2013-3-13.\n",
      "Today is 27 Nov 2012. PyCon starts 13 Mar 2013.\n",
      "Today is 2012年11月27日. PyCon starts 2013年3月13日. 替换了2次\n"
     ]
    }
   ],
   "source": [
    "# 字符串搜索和替换\n",
    "# 简单的\n",
    "from calendar import month_abbr\n",
    "import re\n",
    "text = 'yeah, but no, but yeah, but no, but yeah'\n",
    "text.replace('yeah', 'yep')\n",
    "\n",
    "# 复杂的\n",
    "text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'\n",
    "# 反斜杠数字比如 \\3 指向前面模式的捕获组号\n",
    "print(re.sub(r'(\\d+)/(\\d+)/(\\d+)', r'\\3年\\1月\\2日', text))\n",
    "\n",
    "# 使用命名分组 ?P<month> 和 \\g<group_name>\n",
    "print(re.sub(r'(?P<month>\\d+)/(?P<day>\\d+)/(?P<year>\\d+)',\n",
    "             r'\\g<year>-\\g<month>-\\g<day>', text))\n",
    "\n",
    "# 更加复杂的替换，可以传递一个替换回调函数(参数是一个 match 对象)来代替\n",
    "\n",
    "\n",
    "def change_date(m):\n",
    "    mon_name = month_abbr[int(m.group(1))]\n",
    "    return '{} {} {}'.format(m.group(2), mon_name, m.group(3))\n",
    "\n",
    "\n",
    "print(re.sub(r'(\\d+)/(\\d+)/(\\d+)', change_date, text))\n",
    "\n",
    "\n",
    "# 除了替换后的结果外，还想知道有多少替换发生了\n",
    "res, n = re.subn(r'(\\d+)/(\\d+)/(\\d+)', r'\\3年\\1月\\2日', text)\n",
    "print(res, f'替换了{n}次')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['PYTHON', 'python', 'Python']\n",
      "UPPER snake, lower snake, Mixed snake\n"
     ]
    }
   ],
   "source": [
    "# 字符串忽略大小写的搜索替换\n",
    "import re\n",
    "text = 'UPPER PYTHON, lower python, Mixed Python'\n",
    "print(re.findall('python', text, flags=re.IGNORECASE))\n",
    "print(re.sub('python', 'snake', text, flags=re.IGNORECASE))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['no.']\n",
      "['no.\" Phone says \"yes.']\n",
      "['no.']\n",
      "['no.', 'yes.']\n"
     ]
    }
   ],
   "source": [
    "# 最短匹配模式\n",
    "import re\n",
    "\n",
    "# 在正则表达式中*操作符是贪婪的，因此匹配操作会查找最长的可能匹配\n",
    "str_pat = re.compile(r'\"(.*)\"')\n",
    "text1 = 'Computer says \"no.\"'\n",
    "print(str_pat.findall(text1))\n",
    "\n",
    "text2 = 'Computer says \"no.\" Phone says \"yes.\"'\n",
    "print(str_pat.findall(text2))\n",
    "\n",
    "# ? 非贪婪\n",
    "str_pat = re.compile(r'\"(.*?)\"')\n",
    "text1 = 'Computer says \"no.\"'\n",
    "print(str_pat.findall(text1))\n",
    "\n",
    "text2 = 'Computer says \"no.\" Phone says \"yes.\"'\n",
    "print(str_pat.findall(text2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[' this is a comment ']\n",
      "[]\n",
      "[(' this is a\\nmultiline comment ', ' ')]\n",
      "[' this is a\\nmultiline comment ']\n"
     ]
    }
   ],
   "source": [
    "# 多行匹配模式\n",
    "comment = re.compile(r'/\\*(.*?)\\*/')\n",
    "text1 = '/* this is a comment */'\n",
    "text2 = '''/* this is a\n",
    "multiline comment */\n",
    "'''\n",
    "# 点(.)不能匹配换行符\n",
    "print(comment.findall(text1))\n",
    "print(comment.findall(text2))\n",
    "\n",
    "# (?:.|\\n) 指定了一个非捕获组 (也就是它定义了一个仅仅用来做匹配，而不能通过单独捕获或者编号的组)\n",
    "comment = re.compile(r'/\\*((?:.|\\n)*?)\\*/')\n",
    "\n",
    "print(comment.findall(text2))\n",
    "\n",
    "# 让正则表达式中的点(.)匹配包括换行符在内的任意字符\n",
    "comment = re.compile(r'/\\*(.*?)\\*/', re.DOTALL)\n",
    "print(comment.findall(text2))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hello quanwei'"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 去掉文本字符串开头，结尾或者中间不想要的字符，比如空白\n",
    "# strip() 方法能用于删除开始或结尾的字符。 \n",
    "# lstrip() 和 rstrip() 分别从左和从右执行删除操作。 \n",
    "# 默认情况下，这些方法会去除空白字符，但是你也可以指定其他字符\n",
    "t = ' -----hello quanwei=====\\n'\n",
    "t.strip(' -=\\n')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "qwenv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
